package net.csdn.business.mirror.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.csdn.business.common.domain.request.mirror.MirrorUserTokenDTO;
import net.csdn.business.common.service.CommonAsyncService;
import net.csdn.business.common.service.SuperServiceImpl;
import net.csdn.business.common.utils.RedisLockUtils;
import net.csdn.business.common.utils.SurvivalClamProcessor;
import net.csdn.business.mirror.SpringBeanUtil;
import net.csdn.business.mirror.common.Constants;
import net.csdn.business.mirror.config.ImportMirrorConfig;
import net.csdn.business.mirror.entity.bean.UserGithubToken;
import net.csdn.business.mirror.entity.bo.github.UserBO;
import net.csdn.business.mirror.enums.UserTokenEnum;
import net.csdn.business.mirror.mapper.UserGithubTokenMapper;
import net.csdn.business.mirror.service.ProjectMirrorDataService;
import net.csdn.business.mirror.service.UserGithubTokenService;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;

@Service
@Slf4j
public class UserGithubTokenServiceImpl extends SuperServiceImpl<UserGithubTokenMapper, UserGithubToken> implements UserGithubTokenService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisLockUtils redisLockUtils;

    @Override
    public UserGithubToken latest(String userId) {
        if (StringUtils.isEmpty(userId)) {
            return null;
        }
        return baseMapper.latest(userId);
    }

    @Override
    public UserGithubToken latest(String userId, Integer type) {
        return latest(userId, null, type);
    }

    @Override
    public UserGithubToken latest(String userId, String token) {
        if (StringUtils.isAnyBlank(userId, token)) {
            return null;
        }
        return latest(userId, token, null);
    }

    @Override
    public UserGithubToken latest(String userId, String token, Integer type) {
        if (StringUtils.isEmpty(userId)) {
            return null;
        }
        QueryWrapper<UserGithubToken> queryWrapper = new QueryWrapper<UserGithubToken>();
        LambdaQueryWrapper<UserGithubToken> lambdaQueryWrapper = queryWrapper.lambda();
        lambdaQueryWrapper.eq(UserGithubToken::getUserId, userId);
        if (Objects.nonNull(type) && type > -1) {
            lambdaQueryWrapper.eq(UserGithubToken::getType, type);
        }
        if (StringUtils.isNotEmpty(token)) {
            lambdaQueryWrapper.eq(UserGithubToken::getData, token);
        }
        queryWrapper.orderBy(true, false, "id");
        Page<UserGithubToken> page = new Page<>(1, 1, false);
        baseMapper.selectPage(page, lambdaQueryWrapper);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return null;
        }
        return page.getRecords().get(0);
    }


    @Override
    public UserGithubToken getValidToken(String userId, Integer type) {
        if(StringUtils.isBlank(userId) || type == null){
            return null;
        }
        LambdaQueryWrapper<UserGithubToken> lambdaQueryWrapper = new QueryWrapper<UserGithubToken>().lambda();
        lambdaQueryWrapper.eq(UserGithubToken::getUserId, userId);
        lambdaQueryWrapper.eq(UserGithubToken::getType, type);
        lambdaQueryWrapper.eq(UserGithubToken::getStatus, 1);
        return  baseMapper.selectOne(lambdaQueryWrapper);
    }

    @Override
    public UserGithubToken getToken(String userId, Integer type) {
        if(StringUtils.isBlank(userId) || type == null){
            return null;
        }
        LambdaQueryWrapper<UserGithubToken> lambdaQueryWrapper = new QueryWrapper<UserGithubToken>().lambda();
        lambdaQueryWrapper.eq(UserGithubToken::getUserId, userId);
        lambdaQueryWrapper.eq(UserGithubToken::getType, type);
        return  baseMapper.selectOne(lambdaQueryWrapper);
    }

    public List<UserGithubToken> getToken(String userId){
        if(StringUtils.isBlank(userId)){
            return null;
        }
        LambdaQueryWrapper<UserGithubToken> lambdaQueryWrapper = new QueryWrapper<UserGithubToken>().lambda();
        lambdaQueryWrapper.eq(UserGithubToken::getUserId, userId);
        lambdaQueryWrapper.eq(UserGithubToken::getStatus, 1);
        return  baseMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    public int addOrUpdate(MirrorUserTokenDTO params) {
        return baseMapper.addOrUpdate(params);
    }

    @Override
    public void execVerifyTokenProducer() {
        //分布式锁，防止多个机器同时执行
        //增加分布式锁，保证任务不被并发执行
        StringBuilder key=new StringBuilder("verify_token");
        //增加分布式锁，防止多实例时候并发执行，锁是30秒，守护线程在三分之二过期时间之前进行续期
        String identifier=redisLockUtils.lock(key.toString(),30);
        if(identifier!=null){
            log.info("---------exec Verify Token Producer task start-------");
            //定义锁的延时守护线程
            SurvivalClamProcessor survivalClamProcessor = new SurvivalClamProcessor(redisLockUtils,key.toString(), 30);;
            //定义守护线程
            Thread survivalThread = new Thread(survivalClamProcessor);
            survivalThread.setDaemon(Boolean.TRUE);
            survivalThread.start();
            try{
                baseMapper.mybatisStreamQuery(new ResultHandler<String>() {
                    @Override
                    public void handleResult(ResultContext<? extends String> resultContext) {
                        //获取用户id
                        String id=resultContext.getResultObject();
                        try {
                            //发送到队列
                            stringRedisTemplate.opsForList().rightPush(Constants.USER_TOKEN_VERIFY_KEY, id);
                        } catch (Exception e) {
                            log.error("------exec Verify Token Producer task id:{},error={}", id,e);
                        }
                    }
                });
            }catch (Exception e){
                e.printStackTrace();
                log.error("---------exec Verify Token Producer task error:{}----",e.getMessage());
            }finally {
                redisLockUtils.unlock(key.toString(),identifier);
            }
            log.info("---------exec Verify Token Producer task is finished-------");
        }else{
            log.info("---------exec Verify Token Producer task is cancled-------");
        }
    }

    @Override
    public void execVerifyTokenConsumer() {
        String id=this.pop();
        if (StringUtils.isEmpty(id)) {
            return;
        }
        //查询当前用户的设置的token
        UserGithubToken userToken=this.getById(Long.valueOf(id));
        if(userToken!=null&&userToken.getStatus().equals(1)){
            UserTokenEnum.Type t = UserTokenEnum.Type.parse(userToken.getType());
            UserBO user = SpringBeanUtil.getBean(t.getThirdApiService()).getUser(userToken.getData());
            String userName=userToken.getThirdUsername();
            if (Objects.isNull(user)) {
                Integer status=0;
                //更新状态
                LambdaUpdateWrapper<UserGithubToken> updateWrapper = new UpdateWrapper<UserGithubToken>().lambda();
                updateWrapper.eq(UserGithubToken::getId, userToken.getId());
                updateWrapper.set(UserGithubToken::getStatus, status);
                baseMapper.update(null,updateWrapper);
            }else {
                String loginUsername=user.getLogin();
                if(!userName.equals(loginUsername)){
                    //更新用户名
                    LambdaUpdateWrapper<UserGithubToken> updateWrapper = new UpdateWrapper<UserGithubToken>().lambda();
                    updateWrapper.eq(UserGithubToken::getId, userToken.getId());
                    updateWrapper.set(UserGithubToken::getThirdUsername, loginUsername);
                    baseMapper.update(null,updateWrapper);
                }
            }
        }
    }


    public String pop() {
        String id = stringRedisTemplate.opsForList().leftPop(Constants.USER_TOKEN_VERIFY_KEY);
        if (StringUtils.isEmpty(id)) {
            return null;
        }
        // 删除重复的值
        stringRedisTemplate.opsForList().remove(Constants.USER_TOKEN_VERIFY_KEY, Integer.MAX_VALUE, id);
        return id;
    }

}
